function RemoGeoLocation() {
	this._remoteSvrUrl = 'https://webapi.amap.com/html/geolocate.html';

	this._callbackList = [];

	this._seqBase = 1;

	this._frameReady = 0;

	this._watchIdMap = {};
}

RemoGeoLocation.prototype = {

	_getSeq : function() {
		return this._seqBase++;
	},
	_onRrameReady : function(callback) {

		if (this._frameReady === 0) {

			if (!this._frameReadyList) {
				this._frameReadyList = [];
			}

			this._frameReadyList.push(callback);

			this._prepareIframe();

			return;
		}

		callback.call(this);
	},
	_prepareIframe : function() {

		if (this._iframeWin) {
			return;
		}

		var ifrm = document.createElement('iframe');

		ifrm.src = this._remoteSvrUrl
				+ (this._remoteSvrUrl.indexOf('?') > 0 ? '&' : '?');

		ifrm.width = '0px';
		ifrm.height = '0px';
		ifrm.style.position = 'absolute';
		ifrm.style.display = 'none';

		var self = this;

		var timeoutId = setTimeout(function() {

			self._frameReady = false;

			self._callbackFrameReadyList();

		}, 5000);

		ifrm.onload = function() {

			clearTimeout(timeoutId);

			self._frameReady = true;

			self._callbackFrameReadyList();

			ifrm.onload = null;
		};

		document.body.appendChild(ifrm);

		this._iframeWin = ifrm.contentWindow;

		window.addEventListener('message', function(e) {

			if (self._remoteSvrUrl.indexOf(e['origin']) !== 0) {
				return;
			}

			self._handleRemoteMsg(e['data']);

		}, false);
	},
	_callbackFrameReadyList : function() {

		if (this._frameReadyList) {

			var list = this._frameReadyList;
			this._frameReadyList = null;

			for (var i = 0, len = list.length; i < len; i++) {
				list[i].call(this, this._frameReady);
			}
		}
	},
	_pickCallback : function(seqNum, keepInList) {

		var callbackList = this._callbackList;

		for (var i = 0, len = callbackList.length; i < len; i++) {

			var cbkInfo = callbackList[i];

			if (seqNum === cbkInfo.seq) {

				if (!keepInList) {
					callbackList.splice(i, 1);
				}

				return cbkInfo;
			}
		}
	},
	_handleRemoteMsg : function(msg) {

		var seqNum = msg['seq'];

		var cbkInfo = this._pickCallback(seqNum, !!msg['notify']);

		if (cbkInfo) {

			cbkInfo.cbk.call(null, msg['error'], msg['result']);

		} else {

			console.warn('Receive remote msg: ', msg);
		}

	},
	_postMessage : function(cmd, args, callback, seq) {

		this._prepareIframe();

		var msg = {
			'cmd' : cmd,
			'args' : args,
			'seq' : seq || this._getSeq()
		};

		this._callbackList.push({
			cbk : callback,
			seq : msg['seq']
		});

		this._onRrameReady(function() {

			if (this._frameReady === true) {

				try {

					this._iframeWin.postMessage(msg, '*');

				} catch (e) {

					this._pickCallback(msg['seq']);

					callback(e);
				}
			} else {

				this._pickCallback(msg['seq']);

				callback({
					'message' : 'iFrame load failed!'
				});
			}
		});
	},
	'getCurrentPosition' : function(succHandler, errHandler, options) {

		this._postMessage('getCurrentPosition', [ options ], function(err,
				result) {

			if (err) {
				if (errHandler) {
					errHandler(err);
				}
				return;
			}
			if (succHandler) {
				succHandler(result);
			}
		});
	},
	'watchPosition' : function(succHandler, errHandler, options) {

		var watchKey = 'wk' + this._getSeq(), cmdSeq = this._getSeq();

		this._watchIdMap[watchKey] = {
			stat : 0,
			seq : cmdSeq
		};

		var self = this;

		this._postMessage('watchPosition', [ options ], function(err, result) {

			var id = null;

			if (result) {
				id = result['id'];
			}

			var watchInfo = self._watchIdMap[watchKey];

			watchInfo.id = id;
			watchInfo.stat = 1;

			if (watchInfo.callbackList) {

				var list = watchInfo.callbackList;
				watchInfo.callbackList = null;

				for (var i = 0, len = list.length; i < len; i++) {
					list[i].call(self, id);
				}
			}

			if (err) {
				if (errHandler) {
					errHandler(err);
				}
				return;
			}

			if (succHandler) {
				succHandler(result['pos']);
			}

		}, cmdSeq);

		return watchKey;
	},
	'clearWatch' : function(watchKey, callback) {

		if (!this._watchIdMap[watchKey]) {
			callback('Id not exists: ' + watchKey);
			return;
		}

		var watchInfo = this._watchIdMap[watchKey];

		var self = this;

		function clearId(id) {

			self._postMessage('clearWatch', [ id ], function(err, result) {

				if (!err) {

					self._pickCallback(watchInfo.seq);

					delete self._watchIdMap[watchKey];
				}

				if (callback) {
					callback(err, result);
				}

			});
		}
		
		if (watchInfo.stat < 1) {

			if (!watchInfo.callbackList) {
				watchInfo.callbackList = [];
			}

			watchInfo.callbackList.push(function(id) {
				clearId(id);
			});

		} else {
			clearId(watchInfo.id);
		}
	}
};